package com.breeze.components.limiter.implementation;

import com.breeze.components.core.exception.CommonException;
import com.breeze.components.limiter.anno.RateLimit;
import com.breeze.components.limiter.enums.LimitType;
import com.breeze.components.redis.util.RedissonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.springframework.stereotype.Component;

/**
 * @author valarchie
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class RedisRateLimitChecker extends AbstractRateLimitChecker {

  @Override
  public void check(RateLimit rateLimit, String combineKey) {
    int time = rateLimit.time();
    int count = rateLimit.count();
    try {
      RateType rateType = RateType.OVERALL;
      if (rateLimit.limitType() == LimitType.CLUSTER) {
        rateType = RateType.PER_CLIENT;
      }
      long number = RedissonUtil.rateLimiter(combineKey, rateType, count, time);
      if (number == -1) {
        throw new CommonException(rateLimit.message());
      }
      log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey);
    } catch (Exception e) {
      if (e instanceof CommonException) {
        throw e;
      } else {
        throw new RuntimeException("服务器限流异常，请稍候再试");
      }
    }
  }

  @Override
  public void tryAcquire(
      Runnable runnable, String combinedKey, int permits, int rateLimit, int rateTime) {
    RRateLimiter rateLimiter = RedissonUtil.getClient().getRateLimiter(combinedKey);
    rateLimiter.trySetRate(RateType.OVERALL, rateLimit, rateTime, RateIntervalUnit.SECONDS);
    if (rateLimiter.tryAcquire(permits)) {
      runnable.run();
    }
  }
}
